// 错误传播
//
// @author 风杨
// @date 22-9-2 上午11:32
// @see <a href="yueny09@163.com">mailTo: yueny09@163.com</a>
//
use std::fs;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{ErrorKind, Read, Write};

// 从文件中读取用户名的函数。如果文件不存在或不能读取，这个函数会将这些错误返回给调用它的代码
pub fn not_exist_file_propagating() -> String {
    println!("###################");
    println!("not_exist_file_propagating");
    println!("###################");
    let rs = read_not_exist_file();

    match rs {
        // 忽略非数字的猜测并重新请求数字而不是让程序崩溃
        Ok(n) => n,
        // _ 是一个通配符值，本例中用来匹配所有 Err 值，不管其中有何种信息
        Err(err) => err.to_string(),
    }
}

// 从文件中读取用户名的函数。如果文件不存在或不能读取，这个函数会将这些错误返回给调用它的代码
pub fn exist_file_propagating() -> String {
    println!("###################");
    println!("exist_file_propagating");
    println!("###################");
    let rs = read_exist_file(
        &String::from("hellob.txt"));

    match rs {
        // 忽略非数字的猜测并重新请求数字而不是让程序崩溃
        Ok(n) => n,
        // _ 是一个通配符值，本例中用来匹配所有 Err 值，不管其中有何种信息
        Err(err) => err.to_string(),
    }
}

fn read_not_exist_file() -> Result<String, io::Error> {
    let f = File::open("helloa.txt");

    let mut f = match f {
        Ok(file) => file,
        Err(e) => return Err(e),
    };

    let mut s = String::new();

    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}

fn read_exist_file(fileName: &String) -> Result<String, io::Error> {
    let f = File::open(fileName);

    let mut f = match f {
        Ok(file) => file,
        Err(e) => match e.kind() {
            // 尝试打开的文件并不存在，则创建文件
            ErrorKind::NotFound => match File::create(fileName) {
                Ok(mut fc) => {
                    println!("create file success:{}", fileName);
                    fc.write("create file".as_bytes()).unwrap();
                    fc
                },
                Err(e) => return Err(e)
            },
            other_error => {
                return Err(e)
            }
        },
    };

    // f 中有了一个文件句柄，函数接着在变量 s 中创建了一个新 String,
    // 并调用文件句柄 f 的 read_to_string 方法来将文件的内容读取到 s 中。
    let mut s = String::new();

    let contents = fs::read_to_string(fileName)
        .expect("Something went wrong reading the file");
    println!("file data:{}", contents);

    let mut f = OpenOptions::new()
        .read(true).write(true).append(true)
        .create(false)
        .open(fileName).unwrap();

    // // read_to_string 方法也返回一个 Result 因为它也可能会失败
    // match f.read_to_string(&mut s) {
    //     Ok(_) => {
    //         fs::remove_file(fileName);
    //         Ok(s)
    //     },
    //     Err(e) => {
    //         Err(e)
    //     },
    // }
    // ==>  等价于 // 传播错误的简写：? 运算符
    f.read_to_string(&mut s)?;
    fs::remove_file(fileName).expect("TODO: panic message");
    Ok(s)



}